import { isNumber, isObject } from "util";

export interface DMC {
    direction: 'E'|'W'|'N'|'S',
    degrees: number,
    minutes: number,
    centiminutes: number
}

export class Lnglat {
    
    private lng: DMC|number;
    private lat: DMC|number;
    private model: 'NUMBER'|'DMC';

    constructor(lng: DMC|number, lat: DMC|number) {
        this.lng = lng;
        this.lat = lat;
        this.model = this.checkModel(lng, lat);
    }

    private checkModel(lng: DMC|number, lat: DMC|number): 'NUMBER'|'DMC' {
        let model: 'NUMBER'|'DMC' = null;
        if(isNumber(lng) && isNumber(lat)) {
            model = "NUMBER";
        } else if(isObject(lng) && isObject(lat)) {
            model = 'DMC';
        } else {
            throw('Data type were error with lng or lat!');
        }
        return model;
    }

    private numberToDmc(value: number, direction: 'E'|'W'|'N'|'S'): DMC {
        const degreesFloat: number = Math.abs(value);
        const degrees: number = Math.floor(degreesFloat);
        const minutesFloat: number = (degreesFloat - degrees) * 60;
        const minutes: number = Math.floor(minutesFloat);
        const centiminutesFloat: number = (minutesFloat - minutes) * 60;
        const centiminutes: number = Math.floor(centiminutesFloat);
        return { direction, degrees, minutes, centiminutes };
    }

    toDMC(): { lng: DMC, lat: DMC } {
        let lng: DMC, lat: DMC;
        if(this.model === 'DMC') {
            lng = <DMC>this.lng;
            lat = <DMC>this.lat;
        } else {
            const north: boolean = this.lat >= 0;
            const east: boolean = this.lng >= 0; 
            lng = this.numberToDmc(<number>this.lng, east ? 'E' : 'W');
            lat = this.numberToDmc(<number>this.lat, north ? 'N' : 'S');
        }
        return { lng, lat };
    }

    toLnglat(): { lng: number, lat: number } {
        let lng: number, lat: number;
        if(this.model === 'NUMBER') {
            lng = <number>this.lng;
            lat = <number>this.lat;
        } else {
            const lngDMC = <DMC>this.lng;
            const latDMC = <DMC>this.lat;
            lng = (Math.floor((lngDMC.degrees + (lngDMC.minutes / 60) + lngDMC.centiminutes / 60 / 60) * 1000000) / 1000000) * (lngDMC.direction === 'E' ? 1 : -1);
            lat = (Math.floor((latDMC.degrees + (latDMC.minutes / 60) + latDMC.centiminutes / 60 / 60) * 1000000) / 1000000) * (latDMC.direction === 'N' ? 1 : -1);
        }
        return { lng, lat };
    }
}
